package com.winning.pmph.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import com.winning.pmph.entity.*;
import com.winning.pmph.mapper.*;
import com.winning.pmph.utils.*;
import com.winning.pmph.vo.BookCatalog;
import com.winning.pmph.vo.IncreaseBookVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Component
@Transactional
public class BookService extends ServiceImpl<BookMapper, Book> {

    @Resource
    private TagService tagService;
    @Resource
    private BookArticleService bookArticleService;
    @Resource
    private BookCatalogItemMapper bookCatalogItemMapper;
    @Resource
    private BookCatalogItemContentMapper bookCatalogItemContentMapper;
    @Resource
    private BookLogMapper bookLogMapper;
    @Resource
    private BookPicMapper bookPicMapper;
    @Resource
    private BookSourceFileMapper bookSourceFileMapper;
    @Resource
    private BookTableMapper bookTableMapper;
    @Resource
    private KnowledgeSyncStatusService knowledgeSyncStatusService;
    @Resource
    private KnowledgeSyncRecordMapper knowledgeSyncRecordMapper;
    @Resource
    private KnowledgeUnitService knowledgeUnitService;
    @Resource
    private Gson gson;
    @Resource
    private PlatformKnowledgeLibMapper platformKnowledgeLibMapper;
    @Resource
    private UserService userService;
    @Resource
    private DataPermissionService bookPermissionService;
    @Resource
    private BookCatalogItemContentService bookCatalogItemContentService;
    @Resource
    private IncreaseBookService increaseBookService;
    @Resource
    private BookCategoryService bookCategoryService;


    /**
     * 图书标注, 完成, 转到素材库状态;
     *
     * @param book
     */
    public void insertMaterial(Book book) {
        Integer unmarkedKnowledgeUnitCount = knowledgeUnitService.lambdaQuery()
                .eq(KnowledgeUnit::getBookId, book.getId())
                .eq(KnowledgeUnit::getCategory, StringUtils.EMPTY)
                .count();
        if (unmarkedKnowledgeUnitCount > 0) {
            throw new RuntimeException("存在未标注素材, 不能完成本次标注");
        }
        knowledgeUnitService.update(Wrappers.lambdaUpdate(KnowledgeUnit.class)
                .set(KnowledgeUnit::getStatus, Const.KNOWLEDGE_UNIT_STATUS_MATERIAL)
                .set(KnowledgeUnit::getSubmitMaterialTime, LocalDateTimeUtil.getNowAsString())
                .eq(KnowledgeUnit::getBookId, book.getId()));
        update(Wrappers.lambdaUpdate(Book.class)
                .set(Book::getMarkedStatus, Const.BOOK_MARKED_STATUS_DONE)
                .eq(Book::getId, book.getId()));
    }

    /**
     * 修改图片url, 保存文章article;
     *
     * @param book
     */
    private void saveBookArticle(Book book) {
        // 图片url;
        String webPath = "/ymer/action/file/showImage?filename=image/book/" + book.getIsbn() + "/pics/";
        // 保存前言内容;
        List<BookArticle> frontArticleList = book.getFrontArticleList();
        if (CollectionUtils.isNotEmpty(frontArticleList)) {
            frontArticleList.stream().forEach(bookArticle -> {
                bookArticle.setBookId(book.getId());
                bookArticle.setSituation(BookArticle.SITUATION_FRONT);
                BookUtil.bindImgSrc(book, bookArticle, webPath, BookArticle.SITUATION_FRONT);
            });
            frontArticleList.forEach(bookArticleService::save);
        }
        // 保存正文内容;
        List<BookArticle> bodyArticleList = book.getBodyArticleList();
        if (CollectionUtils.isNotEmpty(bodyArticleList)) {
            bodyArticleList.stream().forEach(bookArticle -> {
                bookArticle.setBookId(book.getId());
                bookArticle.setSituation(BookArticle.SITUATION_BODY);
                BookUtil.bindImgSrc(book, bookArticle, webPath, BookArticle.SITUATION_BODY);
            });
            bodyArticleList.forEach(bookArticleService::save);
        }
        // 保存后记内容;
        List<BookArticle> backArticleList = book.getBackArticleList();
        if (CollectionUtils.isNotEmpty(backArticleList)) {
            backArticleList.stream().forEach(bookArticle -> {
                bookArticle.setBookId(book.getId());
                bookArticle.setSituation(BookArticle.SITUATION_BACK);
                BookUtil.bindImgSrc(book, bookArticle, webPath, BookArticle.SITUATION_BACK);
            });
            backArticleList.forEach(bookArticleService::save);
        }
    }

    private void saveBookPic(Book book) {
        book.getBookPicList().forEach(pic -> pic.setBookId(book.getId()));
        book.getBookTableList().forEach(table -> table.setBookId(book.getId()));
        book.getBookPicList().forEach(bookPicMapper::insert);
        book.getBookTableList().forEach(bookTableMapper::insert);
    }

    private void saveBookCatalog(Book book, BookCatalog bookCatalog) {
        List<BookArticle> articleList = bookArticleService.lambdaQuery()
                .select(BookArticle::getId, BookArticle::getSituation, BookArticle::getSequenceNumber)
                .eq(BookArticle::getBookId, book.getId()).list().stream().collect(Collectors.toList());
        // 图片url;
        String webPath = "/ymer/action/file/showImage?filename=image/book/" + book.getIsbn() + "/pics/";
        // frontCatalogItem;
        List<BookCatalogItem> frontCatalogItemList = bookCatalog.getFrontCatalogItemList();
        // 设置front部分book_article_id;
        if (CollectionUtils.isNotEmpty(frontCatalogItemList)) {
            setArticleField(book, frontCatalogItemList, book.getFrontArticleList(), webPath);
            // 判断是否有article不属于任何目录
            List<String> list = frontCatalogItemList.stream().map(BookCatalogItem::getBookArticleId).collect(Collectors.toList());
            Optional<BookArticle> first = articleList.stream().filter(articleItem -> BookArticle.SITUATION_FRONT.equals(articleItem.getSituation())
                    && !list.contains(articleItem.getId())).findFirst();
            if (first.isPresent()) {
                throw new RuntimeException("sequenceNumber:" + first.get().getSequenceNumber() + "没有对应目录");
            }
            frontCatalogItemList.forEach(bookCatalogItemMapper::insert);
            // 保存内容;
            List<BookCatalogItemContent> bookCatalogItemContents = frontCatalogItemList.stream().map(BookCatalogItem::getBookCatalogItemContent).collect(Collectors.toList());
            bookCatalogItemContents.forEach(bookCatalogItemContentMapper::insert);
        }
        BookUtil.importBookPercentageMap.put(book.getId(), 45);
        // bodyCatalogItem;
        List<BookCatalogItem> bodyCatalogItemList = bookCatalog.getBodyCatalogItemList();
        // 设置body部分book_article_id;
        if (CollectionUtils.isNotEmpty(bodyCatalogItemList)) {
            setArticleField(book, bodyCatalogItemList, book.getBodyArticleList(), webPath);
            // 判断是否有article不属于任何目录
            List<String> list = bodyCatalogItemList.stream().map(BookCatalogItem::getBookArticleId).collect(Collectors.toList());
            Optional<BookArticle> first = articleList.stream().filter(articleItem -> BookArticle.SITUATION_BODY.equals(articleItem.getSituation())
                    && !list.contains(articleItem.getId())).findFirst();
            if (first.isPresent()) {
                throw new RuntimeException("sequenceNumber:" + first.get().getSequenceNumber() + "没有对应目录");
            }
            BookUtil.importBookPercentageMap.put(book.getId(), 50);
            bodyCatalogItemList.forEach(bookCatalogItemMapper::insert);
            BookUtil.importBookPercentageMap.put(book.getId(), 65);
            // 保存内容;
            List<BookCatalogItemContent> bookCatalogItemContents = bodyCatalogItemList.stream().map(BookCatalogItem::getBookCatalogItemContent).collect(Collectors.toList());
            bookCatalogItemContents.forEach(bookCatalogItemContentMapper::insert);
        }
        BookUtil.importBookPercentageMap.put(book.getId(), 80);
        // backCatalogItem;
        List<BookCatalogItem> backCatalogItemList = bookCatalog.getBackCatalogItemList();
        // 设置back部分book_article_id;
        if (CollectionUtils.isNotEmpty(backCatalogItemList)) {
            setArticleField(book, backCatalogItemList, book.getBackArticleList(), webPath);
            // 判断是否有article不属于任何目录
            List<String> list = backCatalogItemList.stream().map(BookCatalogItem::getBookArticleId).collect(Collectors.toList());
            Optional<BookArticle> first = articleList.stream().filter(articleItem -> BookArticle.SITUATION_BACK.equals(articleItem.getSituation())
                    && !list.contains(articleItem.getId())).findFirst();
            if (first.isPresent()) {
                throw new RuntimeException("sequenceNumber:" + first.get().getSequenceNumber() + "没有对应目录");
            }
            backCatalogItemList.forEach(bookCatalogItemMapper::insert);
            // 保存内容;
            List<BookCatalogItemContent> bookCatalogItemContents = backCatalogItemList.stream().map(BookCatalogItem::getBookCatalogItemContent).collect(Collectors.toList());
            bookCatalogItemContents.forEach(bookCatalogItemContentMapper::insert);
        }
        BookUtil.importBookPercentageMap.put(book.getId(), 85);
    }

    private void setArticleField(Book book, List<BookCatalogItem> catalogItemList, List<BookArticle> bookArticleList, String webPath) {
        // 准备 sequenceNumber -> entity 映射;
        Map<String, BookCatalogItem> sequenceNumber2EntityMap = catalogItemList.stream().collect(Collectors.toMap(BookCatalogItem::getSequenceNumber, Function.identity()));
        for (BookCatalogItem bookCatalogItem : catalogItemList) {
            // 后续parentId需要使用, 在此赋值id;
            bookCatalogItem.setId(IdWorker.getIdStr());
            // 如果不是一级目录, 则设置父id;
            if (bookCatalogItem.getLayer() != 1) {
                String parentSequenceNumber = bookCatalogItem.getSequenceNumber().substring(0, bookCatalogItem.getSequenceNumber().lastIndexOf("-"));
                bookCatalogItem.setParentId(sequenceNumber2EntityMap.get(parentSequenceNumber).getId());
            }
            bookCatalogItem.setBookId(book.getId());
            // 通过catalogItemSequenceNumber查找articleSequenceNumber;
            Optional<BookArticle> bookArticleOptional = bookArticleList.stream()
                    .filter(article -> Objects.nonNull(article.getUnitContentDom().getElementById("CHP" + bookCatalogItem.getSequenceNumber())))
                    .findFirst();
            if (bookArticleOptional.isPresent()) {
                BookArticle bookArticle = bookArticleOptional.get();
                bookCatalogItem.setBookArticleId(bookArticle.getId());
                bookCatalogItem.setBookArticleSequenceNumber(bookArticle.getSequenceNumber());
                // 处理目录中包含的图片
                bindCataImgSrc(bookCatalogItem, book, webPath);
                // 解析article, 找到当前目录对应的内容;
                bindCatalogItem(bookCatalogItem, bookArticle.getUnitContentDom());
            } else {
                throw new RuntimeException("图书:" + book.getName() + "的目录项:" +
                        bookCatalogItem.getSequenceNumber() + "---" + bookCatalogItem.getLayer() + "无对应内容!");
            }
        }
        // 判断子目录 父节点是否都存在;
        Set<String> bookCatalogItemIdSet = catalogItemList.stream().map(BookCatalogItem::getId).collect(Collectors.toSet());
        Optional<BookCatalogItem> noParentItemOptional = catalogItemList.stream()
                .filter(item -> item.getLayer() > 1)
                .filter(item -> !bookCatalogItemIdSet.contains(item.getParentId()))
                .findAny();
        if (noParentItemOptional.isPresent()) {
            throw new RuntimeException("图书:" + book.getName() + "的目录项: " +
                    noParentItemOptional.get().getSequenceNumber() + "---" +
                    noParentItemOptional.get().getStr() + " 无对应父目录!");
        }
    }

    /**
     * 处理图书目录包含的图片
     *
     * @param bookCatalogItem
     * @param book
     * @param picsTargetDirPath
     */
    private void bindCataImgSrc(BookCatalogItem bookCatalogItem, Book book, String picsTargetDirPath) {
        Document contentDocument = Jsoup.parse(bookCatalogItem.getStr().replaceAll("<Table", "<IMG"));
        Elements imgElements = contentDocument.getElementsByTag("img");
        imgElements.forEach(ele -> {
            // 因图片路径不一致，这里做兼容处理 src="图片名称" src="pics/图片名称"
            // src属性带后缀名， id不带后缀名
            String picName = StringUtils.defaultIfBlank(ele.attr("src"), ele.attr("id"));
            if (StringUtils.isBlank(picName)) {
                throw new RuntimeException("图书: " + book.getName() + ", 内容: " + bookCatalogItem.getStr() + ", 引用生僻字路径为空");
            }
            // 自动添加后缀,默认添加.jpg
            picName = picName.contains(".") ? picName : (picName + ".jpg");
            picName = picName.substring(picName.lastIndexOf("/") + 1);
            if (!book.getPictureSet().contains(picName)) {
                throw new RuntimeException("图书: " + book.getName() + ", 内容: " + bookCatalogItem.getStr() + ", 引用生僻字:" + picName + "不存在");
            }
            ele.attr("src", picsTargetDirPath + picName);
            ele.attr("class", "BZ");
        });
        bookCatalogItem.setStr(contentDocument.body().html());
    }

    private void bindCatalogItem(BookCatalogItem bookCatalogItem, Document document) {
        BookCatalogItemContent bookCatalogItemContent = new BookCatalogItemContent();
        bookCatalogItemContent.setBookArticleId(bookCatalogItem.getBookArticleId());
        bookCatalogItemContent.setId(bookCatalogItem.getId());
        bookCatalogItem.setBookCatalogItemContent(bookCatalogItemContent);
        Element cntElement = document.getElementById("CHP" + bookCatalogItem.getSequenceNumber());
        if (Objects.isNull(cntElement)) {
            return;
        }
        bookCatalogItemContent.setTitle(cntElement.outerHtml());
        String articlePart = "";
        while (Objects.nonNull(cntElement.nextElementSibling())) {
            cntElement = cntElement.nextElementSibling();
            if (cntElement.hasAttr("id") && cntElement.attr("id").startsWith("CHP")) {
                break;
            }
            articlePart += System.getProperty("line.separator") + cntElement.outerHtml();
        }
        bookCatalogItemContent.setContent(StringUtils.removeStart(articlePart, System.getProperty("line.separator")));
    }

    public void publishBook(String bookId) {
        Book book = getById(bookId);
        // 如果是增值 需判断书名,选题号,封面 增值+电子书  需判断书名,选题号,isbn,封面
        if (!Const.BOOK_TYPE_ELECTRONIC.equals(book.getBookType())) {
            JSONObject increaseData = book.getMetadata().getJSONObject("increase");
            if (StringUtils.isBlank(increaseData.getString("bookName"))) {
                throw new RuntimeException("增值书名不能为空");
            }
            if (StringUtils.isBlank(increaseData.getString("topicNumber"))) {
                throw new RuntimeException("增值选题号不能为空");
            }
            if (Const.BOOK_TYPE_ELECTRONIC_AND_INCREASE.equals(book.getBookType()) && StringUtils.isBlank(increaseData.getString("isbn"))) {
                throw new RuntimeException("增值ISBN不能为空");
            }
            if (StringUtils.isBlank(increaseData.getString("indexImg"))) {
                throw new RuntimeException("增值封面不能为空");
            }
            // 修改图书质检状态
            book.setQualityStatus(Const.BOOK_QUALITY_STATUS_FUXING);
        }
        // 如果是电子书  电子书+增值  需判断价格
        if (!Const.BOOK_TYPE_INCREASE.equals(book.getBookType())) {
            if (StringUtils.isBlank(book.getMetadata().getJSONObject("Price").getString("B_price"))) {
                throw new RuntimeException("电子书价格不能为空");
            }
        }
        book.setStatus(Book.BOOK_STATUS_PUBLISHED);
        book.setVersion(book.getVersion() + 1);
        saveOrUpdate(book);
        // 插入日志;
        String content = PMPHAppUtil.getCurrentUserCnName() + " 发布了图书";
        saveBookLog(book.getId(), content, PMPHAppUtil.getCurrentUserEnName());
        // 修改同步状态;
        List<PlatformKnowledgeLib> platformKnowledgeLibs = platformKnowledgeLibMapper.lambdaQuery().eq(PlatformKnowledgeLib::getKnowledgeLibId, KnowledgeLib.BOOK_LIB_ID).list();
        for (PlatformKnowledgeLib platformKnowledgeLib : platformKnowledgeLibs) {
            // 如果自动同步, 则立即同步;
            if (platformKnowledgeLib.isAutosyncFlag()) {
                syncBook(bookId, platformKnowledgeLib.getPlatformId(), PMPHAppUtil.getCurrentUserEnName());
            }
            // 如果非自动同步, 则修改同步状态为待同步;
            else {
                knowledgeSyncStatusService.update(Wrappers.lambdaUpdate(KnowledgeSyncStatus.class).set(KnowledgeSyncStatus::getKind, KnowledgeSyncStatus.FAILED_KIND_WAITING)
                        .eq(KnowledgeSyncStatus::getKnowledgeId, bookId)
                        .eq(KnowledgeSyncStatus::getPlatformId, platformKnowledgeLib.getPlatformId()));
            }
        }
    }


    public void revokePublish(String bookId) {
        Book book = getById(bookId);
        book.setStatus(Book.BOOK_STATUS_UNPUBLISHED);
        updateById(book);
        // 插入日志;
        String content = PMPHAppUtil.getCurrentUserCnName() + " 撤销发布图书";
        saveBookLog(bookId, content, PMPHAppUtil.getCurrentUserEnName());
    }


    public void deleteBookById(String id, String type) {
        // 根据ID查询图书类型
        Book book = getById(id);
        // 已经发布的图书不能删除
        if (Book.BOOK_STATUS_PUBLISHED == book.getStatus()) {
            throw new RuntimeException("已经发布的图书不能删除");
        }
        // 删除时,需判断来源,如果是增值,只能删除增值类型的图书,如果是增值+电子书,只能在图书模块删除
        if ("increase".equals(type) && Const.BOOK_TYPE_ELECTRONIC_AND_INCREASE.equals(book.getBookType())) {
            throw new RuntimeException("【电子书+增值】类型的图书只能在图书模块删除");
        }
        // 删除图书
        removeById(id);
        // 删除article
        bookArticleService.remove(Wrappers.lambdaQuery(BookArticle.class)
                .eq(BookArticle::getBookId, id));
        // 删除目录
        bookCatalogItemMapper.delete(Wrappers.lambdaQuery(BookCatalogItem.class).eq(BookCatalogItem::getBookId, id));
        bookCatalogItemContentService.removeByIds(bookCatalogItemContentService.lambdaQuery().select(BookCatalogItemContent::getId).exists("select 1 from book_article where book_catalog_item_content.book_article_id = book_article.id and book_id = '" + id + "'")
                .list().stream().map(BookCatalogItemContent::getId).collect(Collectors.toList()));
        bookPicMapper.delete(Wrappers.lambdaQuery(BookPic.class).eq(BookPic::getBookId, id));
        bookTableMapper.delete(Wrappers.lambdaQuery(BookTable.class).eq(BookTable::getBookId, id));
        // 插入日志;
        String content = PMPHAppUtil.getCurrentUserCnName() + " 删除图书";
        saveBookLog(id, content, PMPHAppUtil.getCurrentUserEnName());
    }

    public Page<Book> queryDraftPage(Book book) {
        LambdaQueryChainWrapper<Book> query = lambdaQuery().ne(Book::getStatus, 1)
                .eq(Objects.nonNull(book.getStatus()), Book::getStatus, book.getStatus())
                .like(StringUtils.isNotBlank(book.getName()), Book::getName, book.getName())
                .like(StringUtils.isNotBlank(book.getIsbn()), Book::getIsbn, book.getIsbn())
                .eq(Objects.nonNull(book.getBookType()), Book::getBookType, book.getBookType())
                .orderByDesc(Book::getCreatedTime).orderByAsc(Book::getId);
        if (CollectionUtils.isNotEmpty(book.getCategory())) {
            query = query.like(Book::getCategory, book.getCategory().get(book.getCategory().size() - 1));
        }
        if (CollectionUtils.isNotEmpty(book.getImportTime())) {
            query = query.ge(Book::getUpdatedTime, book.getImportTime().get(0))
                    .le(Book::getUpdatedTime, book.getImportTime().get(1));
        }
        query = bookPermissionService.filterByBookPermission(query);
        return query.page(new Page<>(book.getCurrentPage(), book.getPageSize()));
    }

    public Page<Book> queryOfficialList(Page<Book> page, String name, String category, String updateTime, String isbn, String syncStatus, String bindingPlatform,String version) {
        List<KnowledgeSyncStatus> knowledgeSyncStatusList = knowledgeSyncStatusService.lambdaQuery()
                .eq(KnowledgeSyncStatus::getKnowledgeLibId, KnowledgeLib.BOOK_LIB_ID)
                .eq(KnowledgeSyncStatus::getPlatformId, bindingPlatform).list();
        LambdaQueryChainWrapper<Book> query = lambdaQuery().eq(Book::getStatus, 1)
                .like(StringUtils.isNotBlank(name), Book::getName, name)
                .eq(StringUtils.isNotBlank(version), Book::getVersion, version)
                .eq(StringUtils.isNotBlank(category) && !Objects.equals(category, "[]"), Book::getCategory, category);
        // 推送列表查询时,根据推送状态的操作时间查询
        if (StringUtils.isNotEmpty(updateTime) && StringUtils.isBlank(bindingPlatform)) {
            query = query.ge(Book::getUpdatedTime, updateTime.split(",")[0].trim())
                    .le(Book::getUpdatedTime, updateTime.split(",")[1].trim());
        }
        query = bookPermissionService.filterByBookPermission(query);
        LambdaQueryChainWrapper<Book> bookLambdaQueryChainWrapper = query.like(StringUtils.isNotBlank(isbn), Book::getIsbn, isbn);
        if (StringUtils.isNotBlank(syncStatus) && Integer.parseInt(syncStatus) != KnowledgeSyncStatus.FAILED_KIND_WAITING) {
            bookLambdaQueryChainWrapper.exists(" select 1 from knowledge_sync_status where knowledge_lib_id = 'book_lib_id' " +
                    " and platform_id = '" + bindingPlatform + "' and book.id = knowledge_sync_status.knowledge_id and kind = " + syncStatus);
        }
        if (StringUtils.isNotBlank(syncStatus) && Integer.parseInt(syncStatus) == KnowledgeSyncStatus.FAILED_KIND_WAITING) {
            bookLambdaQueryChainWrapper.notExists(" select 1 from knowledge_sync_status where knowledge_lib_id = 'book_lib_id' " +
                    " and platform_id = '" + bindingPlatform + "' and book.id = knowledge_sync_status.knowledge_id and kind != " + syncStatus);
        }
        if (StringUtils.isNotBlank(bindingPlatform) && StringUtils.isNotBlank(updateTime)) {
            bookLambdaQueryChainWrapper.exists(StringUtils.isNotBlank(bindingPlatform) && StringUtils.isNotBlank(updateTime), " select 1 from knowledge_sync_status where knowledge_lib_id = 'book_lib_id' " +
                    " and platform_id = '" + bindingPlatform + "' and book.id = knowledge_sync_status.knowledge_id and operated_time >= '" + updateTime.split(",")[0].trim() + "' and " +
                    " operated_time <= '" + updateTime.split(",")[1].trim() + "'");
        }
        Page<Book> bookPage = bookLambdaQueryChainWrapper.orderByDesc(Book::getUpdatedTime).orderByAsc(Book::getId).page(page);
        if (CollectionUtils.isNotEmpty(knowledgeSyncStatusList)) {
            Map<String, KnowledgeSyncStatus> map = knowledgeSyncStatusList.stream().collect(Collectors.toMap(KnowledgeSyncStatus::getKnowledgeId, Function.identity()));
            bookPage.getRecords().forEach(t -> {
                t.setSyncStatus(KnowledgeSyncStatus.FAILED_KIND_WAITING);
                if (Objects.nonNull(map.get(t.getId()))) {
                    t.setSyncStatus(map.get(t.getId()).getKind());
                    t.setOperatedTime(map.get(t.getId()).getOperatedTime());
                }
            });
        }
        return bookPage;
    }

    private void saveBookLog(String bookId, String content, String userName) {
        BookLog bookLog = new BookLog();
        bookLog.setBookId(bookId);
        bookLog.setContent(content);
        bookLog.setCreatedBy(userName);
        bookLog.setCreatedTime(LocalDateTimeUtil.getNowAsString());
        bookLogMapper.insert(bookLog);
    }


    public Page<BookSourceFile> queryImportFileList(String status, String updateTime, String bookName, int currentPage, int pageSize, String statusType) {
        LambdaQueryWrapper<BookSourceFile> query = Wrappers.lambdaQuery(BookSourceFile.class)
                .eq(StringUtils.isNotBlank(status), BookSourceFile::getStatus, status)
                .like(StringUtils.isNotBlank(bookName), BookSourceFile::getName, bookName)
                .orderByDesc(BookSourceFile::getUpdatedTime).orderByAsc(BookSourceFile::getId);
        if (StringUtils.isNotEmpty(updateTime)) {
            query = query.ge(BookSourceFile::getUpdatedTime, updateTime.split(",")[0].trim())
                    .le(BookSourceFile::getUpdatedTime, updateTime.split(",")[1].trim());
        }
        Page<BookSourceFile> page = null;
        if (StringUtils.equals(statusType, "all")) {
            page = bookSourceFileMapper.selectPage(new Page<>(), query);
        } else {
            page = bookSourceFileMapper.selectPage(new Page<>(currentPage, pageSize), query);
        }
        return page;
    }

    /**
     * 批量更新元数据
     */

    public void batchUpdateMetadata(Map<String, JSONObject> isbn2MetadataMap) {
        isbn2MetadataMap.forEach((key, value) -> {
            String sql = "update book set name = ?, category = ?, metadata = ? where isbn = ?";
            String bookName = (String) ((JSONObject) value.get("Titles")).get("Main_Title");
            JSONArray category = value.getJSONArray("Category");
            Book book = lambdaQuery().eq(Book::getIsbn, key).one();
            book.setName(bookName);
            book.setCategory(category);
            book.setMetadata(value);
            updateById(book);
        });
    }

    /**
     * 修改metadata;
     *
     * @param metadata
     * @param id
     */

    public void updateMetadata(JSONObject metadata, String id) {
        String bookName = (String) ((JSONObject) metadata.get("Titles")).get("Main_Title");
        JSONArray category = metadata.getJSONArray("Category");
        Book book = getById(id);
        book.setName(bookName);
        book.setCategory(category);
        book.setMetadata(metadata);
        updateById(book);
    }


    public boolean syncBook(String id, String bindingPlatform, String userName) {
        // 先同步book_metadata元数据信息;
        Book book = getById(id);
        // 图书分类, 转换为原格式;
        parseBookCategoryOri(book);
        JSONObject jsonObject = book.getSyncMetadata();
        jsonObject.put("id", id);
        jsonObject.put("version", book.getVersion());
        jsonObject.put("bookType", book.getBookType());
        String metadata = jsonObject.toJSONString();
        boolean sendFlag = RocketMQProducerUtil.sendMessage(bindingPlatform, "book_metadata", book.getName(), metadata);
        if (!sendFlag) {
            insertSync(book, userName, sendFlag, bindingPlatform);
            book.setUpdatedBy(userName);
            book.setUpdatedTime(LocalDateTimeUtil.getNowAsString());
            updateById(book);
            return false;
        }
        // 增值图书只推送图书元数据
        if (!Const.BOOK_TYPE_INCREASE.equals(book.getBookType())) {
            // 文章内容;
            List<BookArticle> bookArticles = bookArticleService.lambdaQuery()
                    .eq(BookArticle::getBookId, id)
                    .orderByAsc(BookArticle::getId).list();
            for (int i = 0; i < bookArticles.size(); i++) {
                BookArticle bookArticle = bookArticles.get(i);
                // 组装数据;
                bookArticle.setIdx(i);
                bookArticle.setVersion(book.getVersion());
                sendFlag = RocketMQProducerUtil.sendMessage(bindingPlatform, "book_article", bookArticle.getTitle(), gson.toJson(bookArticle));
                if (!sendFlag) {
                    insertSync(book, userName, sendFlag, bindingPlatform);
                    book.setUpdatedBy(userName);
                    book.setUpdatedTime(LocalDateTimeUtil.getNowAsString());
                    updateById(book);
                    return false;
                }
            }
            // 同步目录;因部分图书目录超过4M，所以每5000条一批进行推送
            LambdaQueryWrapper<BookCatalogItem> wrapper = Wrappers.lambdaQuery(BookCatalogItem.class)
                    .select(BookCatalogItem::getId,
                            BookCatalogItem::getBookId,
                            BookCatalogItem::getBookArticleId,
                            BookCatalogItem::getSequenceNumber,
                            BookCatalogItem::getLayer,
                            BookCatalogItem::getStr,
                            BookCatalogItem::getSituation,
                            BookCatalogItem::getParentId)
                    .eq(BookCatalogItem::getBookId, book.getId());
            List<BookCatalogItem> bookCatalogItemList = bookCatalogItemMapper.selectList(wrapper);
            bookCatalogItemList.forEach(bookCatalogItem -> bookCatalogItem.setVersion(book.getVersion()));
            List<List<BookCatalogItem>> divisionList = ListDivisionUtil.divisionList(bookCatalogItemList, 5000);
            for (List<BookCatalogItem> itemList : divisionList) {
                String body = gson.toJson(itemList);
                sendFlag = RocketMQProducerUtil.sendMessage(bindingPlatform, "book_catalog", book.getName() + "_catalog", body);
                if (!sendFlag) {
                    insertSync(book, userName, sendFlag, bindingPlatform);
                    book.setUpdatedBy(userName);
                    book.setUpdatedTime(LocalDateTimeUtil.getNowAsString());
                    updateById(book);
                    return false;
                }
            }
        }
        // 同步成功;
        insertSync(book, userName, sendFlag, bindingPlatform);
        updateById(book);
        return true;
    }

    // 修改metadata中 category, 为旧格式, 用于同步;
    private void parseBookCategoryOri(Book book) {
        JSONObject metadata = JSON.parseObject(JSON.toJSONString(book.getMetadata()));
        // 修改电子书分类格式
        metadata.put("Category", setCategoryFormat(book.getCategory(), new BookCategory(), book.getIsbn(), book.getName()));
        JSONObject increaseObject = metadata.getJSONObject("increase");
        // 修改增值分类格式
        increaseObject.put("category", setCategoryFormat(increaseObject.getJSONArray("category"),
                new BookCategory(), increaseObject.getString("isbn"), increaseObject.getString("bookName")));
        book.setSyncMetadata(metadata);
    }

    private BookCategory setCategoryFormat(JSONArray category, BookCategory bookCategory, String isbn, String name) {
        if (CollectionUtils.isNotEmpty(category)) {
            bookCategory.setBiaozhunshuhao(isbn);
            bookCategory.setZhipinmingcheng(name);
            String yijifenlei = category.getString(0);
            bookCategory.setZhipinyijifenleibianhao(yijifenlei);
            bookCategory.setZhipinyijifenlei(tagService.getById(yijifenlei).getName());
            if (category.size() > 1) {
                String erjifenlei = category.getString(1);
                bookCategory.setZhipinerjifenleibianhao(erjifenlei);
                bookCategory.setZhipinerjifenlei(tagService.getById(erjifenlei).getName());
            }
            if (category.size() > 2) {
                String sanjifenlei = category.getString(2);
                bookCategory.setZhipinerjifenleibianhao(sanjifenlei);
                bookCategory.setZhipinerjifenlei(tagService.getById(sanjifenlei).getName());
            }
            if (category.size() > 3) {
                String sijifenlei = category.getString(3);
                bookCategory.setZhipinerjifenleibianhao(sijifenlei);
                bookCategory.setZhipinerjifenlei(tagService.getById(sijifenlei).getName());
            }
        }
        return bookCategory;
    }

    /**
     * 准备知识同步日志对象, 同步状态对象;
     *
     * @param book
     * @param userName
     * @param sendFlag
     * @return
     */
    private void insertSync(Book book, String userName, boolean sendFlag, String bindingPlatform) {
        KnowledgeSyncRecord knowledgeSyncRecord = new KnowledgeSyncRecord();
        knowledgeSyncRecord.setKnowledgeId(book.getId());
        knowledgeSyncRecord.setPlatformId(bindingPlatform);
        knowledgeSyncRecord.setOperatedBy(userName);
        knowledgeSyncRecord.setVersion(book.getVersion());
        knowledgeSyncRecord.setOperatedTime(LocalDateTimeUtil.getNowAsString());
        KnowledgeSyncStatus knowledgeSyncStatus = JSON.parseObject(JSON.toJSONString(knowledgeSyncRecord), KnowledgeSyncStatus.class);
        knowledgeSyncStatus.setKnowledgeLibId(KnowledgeLib.BOOK_LIB_ID);
        // 改状态;
        if (sendFlag) {
            knowledgeSyncRecord.setSyncFlag(KnowledgeSyncRecord.SYNC_STATUS_SUCCESS);
            knowledgeSyncStatus.setKind(KnowledgeSyncStatus.KIND_SUCCESS);
        } else {
            knowledgeSyncRecord.setSyncFlag(KnowledgeSyncRecord.SYNC_STATUS_FAILURE);
            knowledgeSyncStatus.setKind(KnowledgeSyncStatus.FAILED_KIND_PRODUCER);
        }
        // 记录同步日志, 同步状态;
        knowledgeSyncRecordMapper.saveBean(knowledgeSyncRecord);
        // 先删除再新增;
        knowledgeSyncStatusService.getBaseMapper().deleteBeansByWherePart(
                "knowledge_id = '" + knowledgeSyncStatus.getKnowledgeId() +
                        "' and platform_id = '" + knowledgeSyncStatus.getPlatformId() + "'");
        knowledgeSyncStatusService.getBaseMapper().saveBean(knowledgeSyncStatus);
    }


    public String getContentByCatalogId(String bookCatalogItemId) {
        BookCatalogItem bookCatalogItem = bookCatalogItemMapper.selectById(bookCatalogItemId);
        // 获取当前对应article;
        BookArticle bookArticle = bookArticleService.getById(bookCatalogItem.getBookArticleId());
        Element crtElement = Jsoup.parse(bookArticle.getUnitContent()).getElementById("CHP" + bookCatalogItem.getSequenceNumber());
        // 内容 不包含第一行(与目录相同)
        String result = "";
        while (true) {
            Element nextSibling = crtElement.nextElementSibling();
            if (Objects.isNull(nextSibling)) {
                // 当前文章遍历结束, 还未取到完整的内容;
                bookArticle = getNextSibling(bookArticle.getBookId(), bookArticle.getId());
                // 下一篇文章不存在, 结束;
                if (Objects.isNull(bookArticle)) {
                    break;
                }
                nextSibling = Jsoup.parse(bookArticle.getUnitContent()).body().children().first();
            }
            if (nextSibling.tagName().toUpperCase().startsWith("H")
                    && !nextSibling.attr("id").startsWith("CHP" + bookCatalogItem.getSequenceNumber())) {
                break;
            }
            result += "\n" + nextSibling.outerHtml();
            crtElement = nextSibling;
        }
        return result;
    }

    public String getKnowledgeUnitContentByCatalogId(String bookCatalogItemId) {
        String catalogContent = getContentByCatalogId(bookCatalogItemId);
        // 映射图片样式;
        Element catalogContentElement = Jsoup.parse(catalogContent).body();
        catalogContentElement.getElementsByTag("img")
                .forEach(img -> {
                    // 图书图片 cls 转 素材图片 cls
                    BookUtil.parseBookImg2KnowledgeUnitImg(img);
                    // 图片设置图题图注;
                    BookUtil.parseBookImgTitle(img);
                });
        return catalogContentElement.html();
    }

    public BookArticle getPreSibling(String bookId, String bookArticleId) {
        return bookArticleService.lambdaQuery()
                .eq(BookArticle::getBookId, bookId)
                .lt(BookArticle::getId, bookArticleId)
                .orderByDesc(BookArticle::getId)
                .last("LIMIT 1").one();
    }

    public BookArticle getNextSibling(String bookId, String bookArticleId) {
        return bookArticleService.lambdaQuery()
                .eq(BookArticle::getBookId, bookId)
                .gt(BookArticle::getId, bookArticleId)
                .orderByAsc(BookArticle::getId)
                .last("LIMIT 1").one();
    }

    public void importXml(Book book, String forceFlag, String header) {
        // 解压图书;
        BookUtil.unzipBook(book, header);
        // 递归查找某一文件夹下同时含有meta.xml，book.xml，book_catalog.xml，pics 4个文件的文件夹，这个文件夹下的
        // 文件才是正确的应该被解析的文件
        String analysisPath = BookUtil.recursiveFindFile(new File(StringUtils.removeEnd(book.getZipPath(), ".zip")));
        if (StringUtils.isBlank(analysisPath)) {
            throw new RuntimeException("未查找到同时包含meta.xml，book.xml，book_catalog.xml，pics的文件夹");
        }
        book.setAnalysisPath(analysisPath);
        // 解析图书, 图书元数据及文章;
        book = BookUtil.parseBook(book);
        // 校验ISBN号是否已存在;
        List<Book> books = lambdaQuery().eq(Book::getIsbn, book.getIsbn()).ne(Book::getId, book.getId()).list();
        if (books.size() > 0) {
            if (Objects.equals("true", forceFlag)) {
                removeByIds(books.stream().map(Book::getId).collect(Collectors.toList()));
            } else {
                throw new RuntimeException("图书ISBN号已存在, 请删除后重新导入!");
            }
        }
        // 保存图书;
        saveOrUpdate(book);
        // 移动图片文件夹;
        String picsTargetDirPath = BookUtil.copyPicAndTable(book);
        // 解析pics包内xml;
        BookUtil.parsePicAndTable(book, new File(picsTargetDirPath));
        // 保存图片;
        saveBookPic(book);
        // 修改文章图片路径并保存;
        saveBookArticle(book);
        // 解析目录;
        BookCatalog bookCatalog = BookUtil.parseBookCatalog(book.getAnalysisPath());
        // 保存目录;
        saveBookCatalog(book, bookCatalog);
        // 修改资源状态;
        book.setStatus(Book.BOOK_STATUS_UNPUBLISHED);
        // 插入日志;
        String content = userService.getUserByUserName(book.getUpdatedBy()).getName() + " 导入图书";
        saveBookLog(book.getId(), content, book.getUpdatedBy());
    }

    public Book insertIncreaseBook(IncreaseBookVo increaseBookVo) {
        // 新增时校验选题号,选题号必须唯一,不确定图书元数据其他字段是否会存在和选题号一致的数据,取出所有元数据中的选题号
        Optional<String> first = lambdaQuery().select(Book::getMetadata)
                .in(Book::getStatus, Book.BOOK_STATUS_UNPUBLISHED, Book.BOOK_STATUS_PUBLISHED)
                .list().stream()
                .map(item -> item.getMetadata().getJSONObject("increase").getString("topicNumber"))
                .filter(item -> increaseBookVo.getTopicNumber().equals(item)).findFirst();
        if (first.isPresent()) {
            throw new RuntimeException("选题号已存在");
        }
        Book book = lambdaQuery().in(Book::getStatus, Book.BOOK_STATUS_UNPUBLISHED, Book.BOOK_STATUS_PUBLISHED)
                .eq(Book::getIsbn, increaseBookVo.getIsbn()).one();
        if (Objects.nonNull(book)) {
            // 如果是已经发布的图书,状态改为取消发布,如果该图书类型是电子书,修改图书类型
            if (Const.BOOK_TYPE_ELECTRONIC.equals(book.getBookType())) {
                book.setBookType(Const.BOOK_TYPE_ELECTRONIC_AND_INCREASE);
            }
            book.setStatus(Book.BOOK_STATUS_UNPUBLISHED);
            updateById(book);
            return book;
        }
        // 如果根据ISBN查不到,新增,默认 hidden = 1 隐藏电子书
        book = new Book();
        book.setId(IdWorker.getIdStr());
        book.setName(increaseBookVo.getBookName());
        book.setIsbn(increaseBookVo.getIsbn());
        book.setBookType(Const.BOOK_TYPE_INCREASE);
        book.setStatus(Book.BOOK_STATUS_UNPUBLISHED);
        book.setCategory(increaseBookVo.getCategory());
        JSONObject metadata = new JSONObject();
        metadata.put("increase", JSON.parseObject(JSON.toJSONString(increaseBookVo, SerializerFeature.WriteNullStringAsEmpty)));
        book.setMetadata(metadata);
        save(book);
        return book;
    }

    public void updateIncreaseMetadata(IncreaseBookVo increaseBookVo) {
        // 选题号必须唯一
        Optional<String> first = lambdaQuery().select(Book::getMetadata).in(Book::getStatus, Book.BOOK_STATUS_UNPUBLISHED, Book.BOOK_STATUS_PUBLISHED)
                .ne(Book::getId, increaseBookVo.getBookId()).list().stream()
                .map(item -> item.getMetadata().getJSONObject("increase").getString("topicNumber"))
                .filter(item -> increaseBookVo.getTopicNumber().equals(item)).findFirst();
        if (first.isPresent()) {
            throw new RuntimeException("选题号已存在");
        }
        // 修改时,判断ISBN号是否已经存在,如果已经存在,报错提示
        if (StringUtils.isNotBlank(increaseBookVo.getIsbn())) {
            if (Objects.nonNull(lambdaQuery().ne(Book::getId, increaseBookVo.getBookId())
                    .eq(Book::getIsbn, increaseBookVo.getIsbn()).one())) {
                throw new RuntimeException("ISBN号已经存在");
            }
        }
        Book book = getById(increaseBookVo.getBookId());
        // 如果是电子书+增值  信息以电子书为准
        if (Const.BOOK_TYPE_ELECTRONIC_AND_INCREASE.equals(book.getBookType())) {
            JSONObject metadata = book.getMetadata();
            metadata.put("increase", JSON.parseObject(JSON.toJSONString(increaseBookVo, SerializerFeature.WriteNullStringAsEmpty)));
        } else {
            // 如果只是增值
            book.setName(increaseBookVo.getBookName());
            book.setIsbn(increaseBookVo.getIsbn());
            book.setCategory(increaseBookVo.getCategory());
            JSONObject metadata = book.getMetadata();
            metadata.put("increase", JSON.parseObject(JSON.toJSONString(increaseBookVo, SerializerFeature.WriteNullStringAsEmpty)));
            book.setMetadata(metadata);
        }
        updateById(book);
        // 同时修改增值服务信息
        IncreaseBook increaseBook = JSON.parseObject(JSON.toJSONString(book.getMetadata().getJSONObject("increase")), IncreaseBook.class);
        increaseBook.setId(book.getId());
        increaseBookService.editBook(increaseBook);
    }

    public Book selectCategoryAndSummaryAndByIsbn(String isbn, Integer bookType) {
        Book book = new Book();
        // 图书分类信息
        book.setCategory(BookUtil.selectCategoryByIsbn(isbn));
        // 图书简介
        BookCategory bookCategory = bookCategoryService.lambdaQuery().eq(BookCategory::getBiaozhunshuhao, isbn).one();
        if (Objects.isNull(bookCategory)) {
            return book;
        }
        book.setSummary(bookCategory.getNeirongtiyao());
        // 如果是增值+电子书,获取电子书价格
        if (Const.BOOK_TYPE_ELECTRONIC_AND_INCREASE.equals(bookType)) {
            Book electronicBook = lambdaQuery().eq(Book::getIsbn, isbn).eq(Book::getStatus, Book.BOOK_STATUS_UNPUBLISHED).one();
            // 电子书没有价格时,才同步价格
            JSONObject priceObject = electronicBook.getMetadata().getJSONObject("Price");
            if (priceObject.getBigDecimal("B_price").compareTo(new BigDecimal(0.00)) == 0) {
                priceObject.put("B_price", bookCategory.getZhipindingjia());
                book.setBPrice(bookCategory.getZhipindingjia());
                // 更新电子书价格
                updateById(electronicBook);
            }
        }
        return book;
    }
}
